﻿using System;
using System.Activities.Core.Presentation;
using System.Activities.Presentation.Metadata;
using System.Activities.Presentation.Toolbox;
using System.Linq;
using System.Reflection;

namespace Headsight.BPMN2WF.GUI.Designer
{
    public class ToolboxUtils
    {
        public static ToolboxControl CreateToolboxControl()
        {
            new DesignerMetadata().Register();

            LoadToolboxIconsForBuiltInActivities();

            var ctrl = new ToolboxControl();

            //add custom activities
            var categoryCustom = new ToolboxCategory("My Activities")
                                                    {
                                                        new ToolboxItemWrapper(typeof (WF.Activities.UserTask)),
                                                        new ToolboxItemWrapper(typeof (WF.Activities.TerminateEndEvent))
                                                    };

            //add all activities
            var categoryFlowchart = new ToolboxCategory("Flowchart")
                                                    {
                                                        new ToolboxItemWrapper(typeof (System.Activities.Statements.Flowchart)),
                                                        new ToolboxItemWrapper(typeof (System.Activities.Statements.FlowSwitch<>)),
                                                        new ToolboxItemWrapper(typeof (System.Activities.Statements.FlowDecision))
                                                    };
            var categoryCollection = new ToolboxCategory("Collection")
                                                     {
                                                         new ToolboxItemWrapper(typeof (System.Activities.Statements.AddToCollection<>)),
                                                         new ToolboxItemWrapper(typeof (System.Activities.Statements.ClearCollection<>)),
                                                         new ToolboxItemWrapper(typeof (System.Activities.Statements.ExistsInCollection<>)),
                                                         new ToolboxItemWrapper(typeof (System.Activities.Statements.RemoveFromCollection<>)),
                                                     };
            var categoryPrimitives = new ToolboxCategory("Primitives")
                                                     {
                                                         new ToolboxItemWrapper(typeof (System.Activities.Statements.Assign)),
                                                         new ToolboxItemWrapper(typeof (System.Activities.Statements.Assign<>)),
                                                         new ToolboxItemWrapper(typeof (System.Activities.Statements.Delay)),
                                                         new ToolboxItemWrapper(typeof (System.Activities.Statements.InvokeMethod)),
                                                         new ToolboxItemWrapper(typeof (System.Activities.Statements.WriteLine)),
                                                     };
            var categoryControlFlow = new ToolboxCategory("ControlFlow")
                                                      {
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.DoWhile)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.ForEach<>)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.If)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.Parallel)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.ParallelForEach<>)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.Pick)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.PickBranch)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.Sequence)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.Switch<>)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.While)),
                                                      };
            var categoryRuntime = new ToolboxCategory("Runtime")
                                                  {
                                                      new ToolboxItemWrapper(typeof (System.Activities.Statements.Persist)),
                                                      new ToolboxItemWrapper(typeof (System.Activities.Statements.TerminateWorkflow)),
                                                      //new ToolboxItemWrapper(typeof(Interop)),
                                                  };
            var categoryTransaction = new ToolboxCategory("Transaction")
                                                      {
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.CancellationScope)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.CompensableActivity)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.Compensate)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.Confirm)),
                                                          new ToolboxItemWrapper(typeof (System.Activities.Statements.TransactionScope)),
                                                      };
            var categoryErrorHandling = new ToolboxCategory("Error Handling")
                                                        {
                                                            new ToolboxItemWrapper(typeof (System.Activities.Statements.Rethrow)),
                                                            new ToolboxItemWrapper(typeof (System.Activities.Statements.Throw)),
                                                            new ToolboxItemWrapper(typeof (System.Activities.Statements.TryCatch)),
                                                        };
            var categoryMessaging = new ToolboxCategory("Messaging")
                                                    {
                                                        new ToolboxItemWrapper(typeof (System.ServiceModel.Activities.Receive)),
                                                        new ToolboxItemWrapper(typeof (System.ServiceModel.Activities.Send)),
                                                        new ToolboxItemWrapper(typeof (System.ServiceModel.Activities.TransactedReceiveScope)),
                                                    };

            ctrl.Categories.Add(categoryCustom);
            ctrl.Categories.Add(categoryPrimitives);
            ctrl.Categories.Add(categoryControlFlow);
            ctrl.Categories.Add(categoryErrorHandling);
            ctrl.Categories.Add(categoryFlowchart);
            ctrl.Categories.Add(categoryRuntime);
            ctrl.Categories.Add(categoryTransaction);
            ctrl.Categories.Add(categoryCollection);
            ctrl.Categories.Add(categoryMessaging);
            return ctrl;
        }

        private static void LoadToolboxIconsForBuiltInActivities()
        {
            var assembly = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "Library\\Microsoft.VisualStudio.Activities.dll");
            var builder = new AttributeTableBuilder();
            var resourceReader = new System.Resources.ResourceReader(assembly.GetManifestResourceStream("Microsoft.VisualStudio.Activities.Resources.resources"));

            foreach (var type in typeof(System.Activities.Activity).Assembly.GetTypes().Where(t => t.Namespace == "System.Activities.Statements"))
            {
                CreateToolboxBitmapAttributeForActivity(builder, resourceReader, type);
            }

            MetadataStore.AddAttributeTable(builder.CreateTable());
        }

        private static void CreateToolboxBitmapAttributeForActivity(AttributeTableBuilder builder, System.Resources.ResourceReader resourceReader, Type builtInActivityType)
        {
            var bitmap = ExtractBitmapResource(resourceReader, builtInActivityType.IsGenericType ? builtInActivityType.Name.Split('`')[0] : builtInActivityType.Name);

            if (bitmap != null)
            {
                var tbaType = typeof(System.Drawing.ToolboxBitmapAttribute);
                var imageType = typeof(System.Drawing.Image);
                var constructor = tbaType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { imageType, imageType }, null);
                var tba = constructor.Invoke(new object[] { bitmap, bitmap }) as System.Drawing.ToolboxBitmapAttribute;
                builder.AddCustomAttributes(builtInActivityType, tba);
            }
        }

        private static System.Drawing.Bitmap ExtractBitmapResource(System.Resources.ResourceReader resourceReader,
                                                                   string bitmapName)
        {
            System.Collections.IDictionaryEnumerator dictEnum = resourceReader.GetEnumerator();
            System.Drawing.Bitmap bitmap = null;
            while (dictEnum.MoveNext())
            {
                if (Equals(dictEnum.Key, bitmapName))
                {
                    bitmap = dictEnum.Value as System.Drawing.Bitmap;
                    if (bitmap != null)
                    {
                        System.Drawing.Color pixel = bitmap.GetPixel(bitmap.Width - 1, 0);
                        bitmap.MakeTransparent(pixel);
                    }
                    break;
                }
            }

            return bitmap;
        }
    }
}
